//------------------------------------------------------------------------------
// winestore version 15
// author Luo Xu on 2014.08.02
// Tested successfully.
//
// modified by zhangwei on 2014.08.02
// - Add config.base
// - Rename Wine as NodeModel in order to distinguish wine object and wine model object.
// - Refactoring the source code.
// modified by zhangwei in 2014.09
// - Refacotored the structure.
// modified by zhangwei on 2014.10.08
// - This version is derived from version 10 directly. The developer revised the 
//   whiole program structure and make it better than ever. Hope it can be a good
//   template for new modules.
// modified by zhangwei on 2014.12.31
// - Revised. Eliminate some old source code. Also simplified some coding.
// modified by zhangwei on 2015.02.13
// - Copied "webapp/winestore-v14*.*" to "webapp/examples/winestore/winestore-v15.*",
//   and upgrade the css, js and rest backend URL with new relative link.
//   This version is the same as v14 except above modifications.
//	 Tested Ok
// - Add reference to "bootstrap.min.js" though it's not mandatory now.
//------------------------------------------------------------------------------

// Save the URL prefix of the current webapp

var config = {
	base: "../../mvc/"
	//base: "/site/mvc"
};

//------------------------------------------------------------------------------
// Service Layer
// for business logic including data access and network communication. 
//------------------------------------------------------------------------------

window.NodeModel = Backbone.Model.extend({
	// you can also uses urlRoot: config.base +　"api/wines". In this way, this 
	// page and js file can be moved into sub folders. 
	urlRoot : config.base + "fdb/nodes",
	
	defaults : {
		"id" : null,
		"owner":"",
		"originname" : "",
		"curname" : "",
		"storageid" : "",
		"nodetype" : "",
		"contenttype" : "",
		"attribute" : "",
		"properties" :"",
		"size" : "",
		"objectstate" : "",
		"rowstate" : "",
		"upduser" : "",
		"upddate" :"",
		"crtuser" :"",
		"crtdate" :"",
	},

	initialize : function() {
		this.bind('validate', function(model, error) {
			alert(error);
		});
	},
	
	// The returned string will be popup by the browser to notify the user.
	validate : function(attributes) {
		if (attributes.curname == '') {
			return "curname can't be null"; 
		}
	}
});

// window.WineCollectionModel = Backbone.Collection.extend({
//	model : NodeModel,
//	url : "api/wines"
// });

// modified by luoxu
// The "client" mode means the collection are fully on the client side. 
// The mode should be "client" to enable client side caching for paging.
//
window.PageableNodeCollectionModel = Backbone.PageableCollection.extend({
	model : NodeModel,
	url : config.base + "fdb/nodes",
	state : {
		pageSize : 10
	},
	mode : "client" 
});

/*
//We extend the Backbone.Model prototype to build our own
var Donut = Backbone.Model.extend({

// We can pass it default values.
defaults : {
 name : null,
 sparkles : false,
 cream_filled : false
},

url : function() {
 // Important! It's got to know where to send its REST calls. 
 // In this case, POST to '/donuts' and PUT to '/donuts/:id'
 return this.id ? '/donuts/' + this.id : '/donuts'; 
} 

});

var Donuts = Backbone.Collection.extend({
	model : Donut,
	url : "/donuts"
});

var donuts = new Donuts([
{"name" : "Boston Cream"},
{"name" : "Lemon-Filled"},
{"name" : "Rusty Iron Shavings"}
]);

*/

//------------------------------------------------------------------------------
// View Layer
// for user interaction. Including render the data in the models to webpage
// and accepting the page input to model for saving. 
//------------------------------------------------------------------------------

// In order to guarantee releasing resources when view is closed
//
Backbone.View.prototype.close = function () {
    console.log('Closing view ' + this);
    if (this.beforeClose) {
        this.beforeClose();
    }
    this.remove();
    this.unbind();
};







window.WineView = Backbone.View.extend({
	
    initialize: function() {
    	this.template = _.template($('#tpl_itemdetail').html());
		this.model.on("change", this.render, this);
    },
    
    render: function() {
		$(this.el).html(this.template(this.model.toJSON()));
		return this;
    },

    events: {
        "change input": "onInputChange",
		"click .save": "onSaveWine",
		"click .cancel": "onCancel"
    },

    onInputChange: function(event) {
        var target = event.target;
        console.log('changing ' + target.id + ' from: ' + target.defaultValue + ' to: ' + target.value);
    },

	onSaveWine: function() {
		this.model.set({
			owner: $('#owner').val,
			originname: $('#originname').val(),
			curname: $('#curname').val(),		
			storageid: $('#storageid').val(),
			nodetype: $('#nodetype').val(),
			contenttype: $('#contenttype').val(),
			attribute: $('#attribute').val(),
			properties: $('#properties').val(),
			size: $('#size').val(),
			objectstate: $('#objectstate').val(),
			rowstate: $('#rowstate').val(),
			upduser: $('#upduser').val(),
			upddate: $('#upddate').val(),
			crtuser: $('#crtuser').val(),
			crtdate: $('#crtdate').val()
		});
		if(!this.model.isValid()){
			alert("originname can't be empty!");
			return false;
		}
		
		// http://stackoverflow.com/questions/16256635/backbone-model-saving-and-callback-issues
		// The model must belong to the pagable wine list
		this.model.save(null, {
			success: function() {
				alert("save successfully!");
				app.navigate('', {trigger: true});
			},
			error: function(error){
				console.log("exception encountered when save data" );
			}
		});

		return false;
	},
	
	onCancel : function(){
		app.navigate('', {trigger :true});
	}
});


BackgridColumns = [{
		// enable the select-all extension of the backgrid component
		name : "",
		cell : "select-row",
		headerCell : "select-all"
	}, {
		name : "id",
		label : "ID",
		editable : false,
		cell : Backgrid.StringCell.extend({
			orderSeparator : ''
		})
	}, 
	{
		name : "originname",
		label : "Originname",
		editable : false,
		cell : Backgrid.StringCell.extend({
			orderSeparator : ''
		})
	}, {
		name : "curname",
		label : "Curname",
		editable : false,
		cell : Backgrid.StringCell.extend({
			orderSeparator : ''
		})
	}, {
		name : "storageid",
		label : "Storageid",
		editable : false,
		cell : Backgrid.StringCell.extend({
			orderSeparator : ''
		})
	}, 
	{
		name : "delete",
		label : "",
		editable : false,
		cell : Backgrid.Cell.extend({
			template : _.template('<button class="btn btn-danger">Delete</button>'),
			events : {
				"click" : "onDeleteRow"
			},
			onDeleteRow : function(e) {
				e.preventDefault();
				this.model.destroy({
					success : function(model, response) {
						alert('Wine deleted successfully ' );
					},
					error: function(error){
							console.log("exception encountered when delete data" );
					}
				});
				return false;
			},
			render : function() {
				this.$el.html(this.template());
				this.delegateEvents();
				return this;
			}
		})
	}, {
		name : "edit",
		label : "",
		editable : false,
		cell : Backgrid.Cell.extend({
			template : _.template('<a href="#wines/<%= this.model.id %>" class="btn btn-primary">Edit</a>'),
			events : {
				"click" : "onEditRow",
			},

			onEditRow : function(e) {
				e.preventDefault();
				//app.navigate("wines/:id", {trigger: true}); 
				app.navigate("wines/" + this.model.id, {trigger: true}); 
				return false;
			},

			render : function() {
				this.$el.html(this.template());
				this.delegateEvents();
				return this;
			}
		})
	}];


// Set up a grid to use the pageable collection
window.WineCollectionView = Backbone.View.extend({
	
	grid: Backgrid.Grid,
	
	// The el and model object are passed in when instantiate this object(new this object).
	// model: winelist,
	
	events:{
		'click #addnew': 'onAddnew',
		'click #deleteselected': 'onDeleteSelected',
	},
	
	initialize: function() {
		console.log("WineCollectionView initialized!");
		
		this.template = _.template($("#tpl_itemlist").html());
		
		/*
		this.model.on("change", this.render, this);
		*/
		
		// this.on("reset", function(collection){
		// 	this.render();
		// });
	},

	render: function(){
		grid = new Backgrid.Grid({
			columns: BackgridColumns,
			collection: this.model 
		});

		//$(this.el).html(this.template(this.model.toJSON()));
		$(this.el).html(this.template());

		$("#backgrid").html( grid.render().el );
		
		var filter = new Backgrid.Extension.ClientSideFilter({
			collection: this.model,
			fields: ['description']
		});
		$("#backgrid").prepend(filter.render().el);
		var paginator = new Backgrid.Extension.Paginator({
			collection: this.model
		});
		$("#backgrid").append(paginator.render().el);
		
		return this;
	},
	
	onAddnew: function(){
		console.log("addnew selected click");
		$('#objecteditor').html( new WineView({model: new NodeModel()}).render().el );
		app.navigate("wines/", true);
	},
	
	onDeleteSelected: function(){
		console.log("delete selected click");	

		var selectedModels = grid.getSelectedModels();
		if (selectedModels == null) {
			alert("Please select what you want to delete first!");
		} 
		else if (selectedModels.length > 5){
			alert("This application doesn't allow you delete objects more than 5! You could only select at most 5");
		}
		else{
			_.each(selectedModels, function(model) {
				model.destroy({
					success: function(model,response){
						console.log("delete selected successfully " + model );
					},
					error: function(error){
						console.log("exception encountered when delete data" );
					}
				})
			});
		}
	}
});


// Tile is defined an area containing object list, object detail and their related 
// operations. It's an integration of object collection view and object item view
// together.
//
// TODO
//
window.WineTile = Backbone.View.extend({
	
	// The el will be passed when instantiate this object.
	// el: $("#winetile"),
	
	initialize: function() {
		this.template = _.template($("#tpl_winetile").html());

		this.model.fetch({
    		success : function(collection, resq, options){
    			console.log('WineTile Fetch successfully.');
    		}
    	});

	},

	render: function()
	{
		this.$el.html(this.template());
    	var view = new WineCollectionView({el:"#objecteditor", model: this.model});
    	view.render();
	},
});

//-----------------------------------------------------------------------------

NodeView = Backbone.View.extend({
	tagName : "div",
	//className : "donut",

	// TODO: change render to use out template as other view does!!!
	render : function() {
		this.el.innerHTML = this.model.get('name'); //todo
		return this;
	}
});

// TODO: NodeView and FdbNode seems can be merged as one 
var FdbNodeView = NodeView.extend({
	initialize : function(options) {
		this.render = _.bind(this.render, this);
		this.model.bind('change:name', this.render);
	}
});

var FdbCollectionView = Backbone.View.extend({
	initialize : function(options) {
		_(this).bindAll('add', 'remove');

		if (!options.childViewConstructor)
			throw "no child view constructor provided";
		if (!options.childViewTagName)
			throw "no child view tag name provided";

		this._childViewConstructor = options.childViewConstructor;
		this._childViewTagName = options.childViewTagName;

		this._childViews = [];

		this.collection.each(this.add);

		this.collection.bind('add', this.add);
		this.collection.bind('remove', this.remove);
	},

	add : function(model) {
		var childView = new this._childViewConstructor({
			tagName : this._childViewTagName,
			model : model
		});

		this._childViews.push(childView);

		if (this._rendered) {
			$(this.el).append(childView.render().el);
		}
	},

	remove : function(model) {
		var viewToRemove = _(this._childViews).select(function(cv) {
			return cv.model === model;
		})[0];
		this._childViews = _(this._childViews).without(viewToRemove);

		if (this._rendered)
			$(viewToRemove.el).remove();
	},

	render : function() {
		var that = this;
		this._rendered = true;

		$(this.el).empty();

		_(this._childViews).each(function(childView) {
			$(that.el).append(childView.render().el);
		});

		return this;
	}
});

//------------------------------------------------------------------------------

var nodes = new PageableNodeCollectionModel({
	// TODO
});

// donutCollectionView seems no use because the new process inside Appview
var donutCollectionView = new FdbCollectionView({
	collection : nodes,
	childViewConstructor : FdbNodeView,
	childViewTagName : 'li',
	el : $('#donut_list')[0] // TODO
});

var AppView = Backbone.View.extend({
	templateId : 'donut_shop',
	initialize : function() {

		// Don't worry about this syntax too much.
		// Basically all that this template bit does is grab a template from
		// jQuery
		// I'll have taken care of compiling the template somewhere earlier.
		this.template = $.template(this.templateId);
		this._donutCollectionView = new FdbCollectionView({
			// collection : this.model.donuts,
			collection : nodes,
			childViewConstructor : FdbNodeView,
			childViewTagName : 'li',
			el : $('#donut_list')[0]
		// TODO
		});
	},

	render : function() {
		$(this.el).empty();

		// And here I use the template to render this object,
		// then take the rendered template
		// and append it to this view's element.
		$.tmpl(this.template, this.model.toJSON()).appendTo(this.el);

		this._donutCollectionView.el = this.$('.donuts'); // TODO
		this._donutCollectionView.render();
	}
});

// var donutShopView = new AppView({ model : donutShop });
var donutShopView = new AppView({
	model : nodes
});







// ------------------------------------------------------------------------------
// Controller Definition
//------------------------------------------------------------------------------

var WineStoreApplication = Backbone.Router.extend({

	// Declare the model variable, so that the view and use it later. 
	// winelist = new window.PageableNodeCollectionModel();
	winelist: null,
	
	routes : {
		'' : 'getItemList',
		"wines/new" : "addNew",
		//"wines/deleteselected" : "deleteSelected",
		"wines/:id" : "editItemDetail",
	},

	initialize : function() {
		winelist = new window.PageableNodeCollectionModel();
	},
	
	showView : function(selector, view) {
		$(selector).empty();
		$(selector).html(view.render().el);
		this.currentView = view;
		return view;
	},
	
	getItemList: function(){
		// attention: I don't know why the backgrid can display data successfully
		// when passing the model here.
		var winetile = new window.WineTile({el: "#winetile", model: winelist});
		winetile.render();
		
		// attention you cannot call app.showView() because the return value of render()
		// method seems not appropriate.
		//app.showView('#winetile', new WineCollectionView());
	},
	
	editItemDetail : function(id) {
		var wine = winelist.get(id);
		if (wine == null)
		{
			alert("editItemDetail: Failed to get the model object! ");
		}
		else{
			app.showView('#objecteditor', new WineView({model : wine}));
		};
	},
	
	addNew : function() {
		console.log("router add new");
		$('#objecteditor').html( new WineView({model: new NodeModel()}).render().el );
		//app.showView('#objecteditor', new WineView({model : new NodeModel()}));
	},
});

$(document).ready(function () {
	app = new WineStoreApplication();
	Backbone.history.start();
});
